ci: centralize Quarto docs build, migrate actions to Node 24#85
Merged
Conversation
The quartodoc -> interlinks -> render -> publish sequence was duplicated
between docs.yml and release.yml, and the two used different concurrency
groups while both pushing to gh-pages — the same race spotforecast2 hit
("cannot lock ref 'refs/heads/gh-pages'", fixed there in 8f8c139).
- New reusable workflow quarto-build.yml (workflow_call) with a job-level
gh-pages-deploy concurrency group shared by every caller, setup-uv
caching (docs.yml previously had none, so each manual rebuild
re-downloaded torch & friends), and uv sync instead of uv pip install.
- docs.yml becomes a thin workflow_dispatch caller; a new deploy=false
input allows render-only dry runs on branches.
- release.yml splits into release (semantic-release + PyPI) and docs jobs;
the docs job builds from main so the rendered site shows the version
just bumped by the chore(release) commit, matching the old in-place
render behavior. Release-job actions bumped to Node 24 releases.
Playbook extracted from spotforecast2 (5212a10, 8f8c139) and
spotforecast2-safe (40ca6947).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GitHub forces all Node 20 actions onto Node 24 on 2026-06-16 and removes
the Node 20 runner on 2026-09-16. Bump every pinned JavaScript action to
its current Node 24 release (still SHA-pinned, version comment updated),
matching spotforecast2-safe 04dbabc8:
actions/checkout v4.x -> v6.0.2
actions/setup-python v5.6.0 -> v6.2.0
astral-sh/setup-uv v5.4.2 -> v8.1.0
actions/upload-artifact v7.0.0 -> v7.0.1
github/codeql-action unified on v3.32.6 (scorecard upload-sarif was
on v3.28.5; codeql.yml already on v3.32.6)
scorecard.yml: drop the push-to-main trigger — the full supply-chain scan
re-ran on every merge without changing the score between weekly runs; the
weekly schedule + branch_protection_rule triggers remain.
Known follow-up: cycjimmy/semantic-release-action is pinned at v4.2.2
(node20 declaration; still runs after the forced migration). Bumping to
v6 changes the underlying semantic-release major and is deferred.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A called workflow may not request more permissions than the caller's job
grants. The workflow-level `permissions: read-all` demanded read on every
scope while docs.yml/release.yml grant only `contents: write`, so every
dispatch died with startup_failure ("Invalid workflow file ... The
workflow is requesting ..."). The job-level `contents: write` declaration
is the complete requirement.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
semantic-release bumps pyproject.toml in its chore(release) commit but does not re-lock, so uv.lock still recorded spotoptim 0.12.4. Every `uv run` then re-locks the file, which dirtied the working tree and made the pre-push pytest hook fail with "files were modified by this hook" despite all tests passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Applies the CI/CD optimization playbook extracted from the local
spotforecast2/spotforecast2-saferepos to spotoptim's pipelines. Builds on the already-shipped optimizations (fast/slow test split, BLAS thread pinning, release-pipeline test removal, setup-uv caching, committed_freeze/) — this PR covers the verified remaining gaps.1. Reusable docs workflow (
quarto-build.yml)docs.ymlandrelease.yml; both now delegate to a singleworkflow_callworkflow.cannot lock ref 'refs/heads/gh-pages'failure spotforecast2 hit (fixed there in8f8c139). All publishes now share one job-levelgh-pages-deploygroup.uv pip install --system, re-downloading torch & friends every time. Nowuv sync+ lockfile-keyed cache.deploy=falsedispatch input gives render-only dry runs on branches without touching production gh-pages.release.ymlis now two jobs (release→docs); the docs job builds frommainso the rendered site includes the version bumped by thechore(release)commit, matching the old in-place render behavior.2. Node 24 action migration (forced by GitHub on 2026-06-16)
SHA-pinned bumps matching spotforecast2-safe
04dbabc8: checkout v6.0.2, setup-python v6.2.0, setup-uv v8.1.0, setup-node v6.4.0, upload-artifact v7.0.1; codeql-action unified on v3.32.6.3. Trigger trim
scorecard.ymlno longer runs on every push to main (weekly schedule +branch_protection_ruleremain). CodeQL's PR trigger is intentionally kept.4. Lockfile sync
uv.lockstill recorded spotoptim 0.12.4 after the 0.12.5 release (semantic-release bumpspyproject.tomlbut doesn't re-lock), so everyuv runre-locked it and the pre-push pytest hook failed with "files were modified by this hook". Synced here.Verification
actionlintclean on all six workflowsgh workflow run docs.yml --ref ci/centralize-docs-node24 -f deploy=falseKnown follow-ups (intentionally deferred)
cycjimmy/semantic-release-actionstays at v4.2.2 (declares node20 but keeps running after the forced migration); bumping to v6 changes the underlying semantic-release major.uv lockand commituv.lockin its release assets to prevent recurring lockfile drift.🤖 Generated with Claude Code